package com.leyou.order.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.auth.pojo.UserHolder;
import com.leyou.common.constants.LyConstants;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Sku;
import com.leyou.order.dto.*;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class OrderService extends ServiceImpl<OrderDetailMapper, OrderDetail> {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;

    @Autowired
    private AmqpTemplate amqpTemplate;


    @GlobalTransactional
    public Long saveOrder(OrderDTO orderDTO) {
        try {
            //保存订单
            //创建订单对象
            Order order = new Order();
            order.setUserId(UserHolder.getUserId());
            order.setStatus(OrderStatusEnum.INIT.value());
            order.setPaymentType(orderDTO.getPaymentType());
            order.setInvoiceType(0);
            order.setSourceType(2);
            order.setPostFee(0L);
            //得到购买的购物车的集合
            List<CartDTO> carts = orderDTO.getCarts();
            //将列表结构的购物车集合转成Map结构
            Map<Long, Integer> cartMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //得到购买的所有sku的对象集合
            List<Long> skuIds = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            List<Sku> skus = itemClient.findSkusByIds(skuIds);
            //计算总金额
            Long totalFee = skus.stream().mapToLong(sku->sku.getPrice()*cartMap.get(sku.getId())).sum();
            order.setTotalFee(totalFee);
            order.setActualFee(1L);
            orderMapper.insert(order);

            //获取订单id
            Long orderId = order.getOrderId();

            //保存订单详情
            List<OrderDetail> orderDetails = new ArrayList<>();
            //遍历sku的集合
            skus.forEach(sku -> {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setOrderId(orderId);
                orderDetail.setSkuId(sku.getId());
                orderDetail.setTitle(sku.getTitle());
                orderDetail.setPrice(sku.getPrice());
                orderDetail.setOwnSpec(sku.getOwnSpec());
                orderDetail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
                orderDetail.setNum(cartMap.get(sku.getId()));
                orderDetails.add(orderDetail);
            });
            saveBatch(orderDetails);

            //保存物流信息
            //获取用户的物流信息
            AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUserId(), orderDTO.getAddressId());
            //将物流的dto对象转成entity对象
            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
            orderLogistics.setOrderId(orderId);
            logisticsMapper.insert(orderLogistics);

            //减库存
            itemClient.minusStock(cartMap);


            /*------------------------------实战--------------------------------------*/
            //创建订单之后将订单同步Redis
            //获取用户id
            String userId = UserHolder.getUserId().toString();
            String key = LyConstants.ORDER_PRE + userId + "0";
            String key1 = LyConstants.ORDER_PRE + userId + "1";

            try{
                BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(key);
                BoundHashOperations<String, Object, Object> hashOps1 = redisTemplate.boundHashOps(key1);
                OrderVIEW orderVIEW = BeanHelper.copyProperties(order, OrderVIEW.class);
                orderVIEW.setOrderDetails(orderDetails);

                hashOps.put(orderId.toString(),JsonUtils.toString(orderVIEW));
                hashOps1.put(orderId.toString(),JsonUtils.toString(orderVIEW));
                log.info("【Redis数据更新】成功！");
            }catch (Exception e){
                log.error("【Redis数据更新】失败！");
            }
            //----------------------------------------------------------------------------


            //int i = 1/0;
            //制定routingKey
            String routingKey = MQConstants.RoutingKey.CART_DELED_KEY;
            //异步操作mq
            amqpTemplate.convertAndSend(MQConstants.Exchange.ORDER_EXCHANGE_NAME, routingKey, UserHolder.getUserId());
            return orderId;
        }catch (Exception e){
            e.printStackTrace();
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

    }

    public OrderVO findOrderById(Long id) {
        Order order = orderMapper.selectById(id);
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //将Order对象转成OrderVO对象
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        //查询订单详情
        OrderDetail entity = new OrderDetail();
        entity.setOrderId(id);
        QueryWrapper<OrderDetail> wrapper = Wrappers.query(entity);
        List<OrderDetail> orderDetails = detailMapper.selectList(wrapper);
        if(CollectionUtils.isEmpty(orderDetails)){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        orderVO.setDetailList(orderDetails);
        //查询物流信息
        OrderLogistics orderLogistics = logisticsMapper.selectById(id);
        if(orderLogistics==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        orderVO.setLogistics(orderLogistics);
        return orderVO;
    }

    public String getPayUrl(Long id) {
        //得到当前订单在redis中存储的支付链接的key
        String key = LyConstants.PAY_URL_PRE+id;
        //通过key获取payUrl
        String payUrl = redisTemplate.opsForValue().get(key);
        //判空
        if(StringUtils.isNotBlank(payUrl)){
            return payUrl;
        }
        //根据id查询订单对象
        Order order = orderMapper.selectById(id);
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //判断订单是否已经支付
        if(!order.getStatus().equals(OrderStatusEnum.INIT.value())){
            throw new LyException(500, "订单已支付！");
        }
        //获取支付链接
        payUrl = payHelper.getPayUrl(id, order.getActualFee());
        //将支付链接放入redis中
        redisTemplate.opsForValue().set(key, payUrl, 2, TimeUnit.HOURS);
        return payUrl;
    }

    public Integer findOrderStatus(Long id) {
        Order order = orderMapper.selectById(id);
        if(order==null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }

    public Map<String, String> wxNotify(Map<String, String> resp) {
        //校验数据
        payHelper.checkResp(resp);
        //获取订单号
        String outTradeNo = resp.get("out_trade_no");
        //获取订单的Long类型
        Long orderId = Long.valueOf(outTradeNo);
        //获取金额
        Long totalFee = Long.valueOf(resp.get("total_fee"));
        //根据订单查询本地数据库订单对象
        Order order = orderMapper.selectById(orderId);
        if(order==null){
            log.error("【支付订单不存在！】");
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //获取订单应付金额
        Long actualFee = order.getActualFee();
        //比对金额
        if(!totalFee.equals(actualFee)){
            log.error("【订单支付金额不一致！】");
            throw new LyException(500, "订单支付金额不一致");
        }
        //修改订单状态
        Order entity = new Order();
        entity.setOrderId(orderId);
        entity.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateById(entity);
        if(count==0){
            log.error("【修改订单状态失败！】");
        }

        //------------------------------------------实战---------------------------------------
        //付款成功订单存放到Redis中变成付款，未付款删除
        try{

            //获取用户id
            String userId = UserHolder.getUserId().toString();
            String key2 = LyConstants.ORDER_PRE + userId + "2";
            String key1 = LyConstants.ORDER_PRE + userId + "1";


            redisTemplate.boundHashOps(key1).delete(orderId.toString());

            Order order1 = orderMapper.selectById(orderId);
            OrderVIEW orderVIEW = BeanHelper.copyProperties(order1, OrderVIEW.class);
            orderVIEW.setUserId(UserHolder.getUserId());

            OrderDetail entity1 = new OrderDetail();
            entity1.setOrderId(orderId);

            QueryWrapper<OrderDetail> wrappers = Wrappers.query(entity1);
            //查询该订单下所有的商品订单详情
            List<OrderDetail> orderDetails = detailMapper.selectList(wrappers);
            orderVIEW.setOrderDetails(orderDetails);
            redisTemplate.boundHashOps(key2).put(orderId.toString(),JsonUtils.toString(orderVIEW));
        }catch (Exception e){
            log.error("【Redis缓存更新】失败！");
        }
        //-------------------------------------------------------------------------------------

        Map<String, String> result = new HashMap<>();
        result.put("return_code", "SUCCESS");
        result.put("return_msg", "OK");
        return result;
    }

    /**
     * 查询所有订单，根据状态
     * */
    public PageResult<OrderVIEW> findAll(Integer status, Integer page, Integer rows) {

        //获取用户id
        Long userId = UserHolder.getUserId();
        //1.分页查询订单
        IPage<Order> iPage = new Page<>(page,rows);


        String name = "0";
        String key = null;
        if (status != null){
            name = status.toString();
        }
        key = LyConstants.ORDER_PRE + userId + name;
        //得到当前key对应的hash
        BoundHashOperations<String, String, String> cartHash = redisTemplate.boundHashOps(key);


        //判断用户订单是否存在,不存在进入数据库查询
        if (cartHash == null || cartHash.size() == 0){
            Order order = new Order();
            order.setUserId(userId);

            if (status != null){
                order.setStatus(status);
            }

            //2.创建一个复杂查询条件
            QueryWrapper<Order> wrapper = Wrappers.query(order);

            //4.查询对应的订单状态数据
            iPage = orderMapper.selectPage(iPage,wrapper);
            List<Order> records = iPage.getRecords();
            //判断集合是否为空
            if (CollectionUtils.isEmpty(records)){
                throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
            }

            //5.将Order集合转成OrderVIEW
            List<OrderVIEW> orderVIEWS = BeanHelper.copyWithCollection(records, OrderVIEW.class);

            //6.查询对应的订单详情封装到OrderVIEW中
            for (OrderVIEW orderVIEW : orderVIEWS) {
                OrderDetail entity = new OrderDetail();
                entity.setOrderId(orderVIEW.getOrderId());
                QueryWrapper<OrderDetail> wrappers = Wrappers.query(entity);
                //查询该订单下所有的商品订单详情
                List<OrderDetail> orderDetails = detailMapper.selectList(wrappers);
                orderVIEW.setOrderDetails(orderDetails);
                /**
                 * 将订单对应的状态信息保存到Redis中
                 * */
                cartHash.put(orderVIEW.getOrderId().toString(), JsonUtils.toString(orderVIEW));
            }

        }


        //如果Redis中有数据，直接拿取
        List<OrderVIEW> collect = cartHash.values().stream().map(orders -> JsonUtils.toBean(orders, OrderVIEW.class)).collect(Collectors.toList());


        //7.创建一个自定义的分页对象
        PageResult<OrderVIEW> orderVIEWPageResult = new PageResult<>(
                iPage.getTotal(),
                iPage.getPages(),
                collect
        );

        return orderVIEWPageResult;
    }
}
